package com.maas.util.mybatis.jpa.littlenb.support.core;


import com.littlenb.mybatisjpa.statement.StatementFactory;
import com.maas.util.mybatis.jpa.littlenb.annotation.mapper.SelectCountDefinition;
import com.maas.util.mybatis.jpa.littlenb.annotation.mapper.SelectDefinition;
import com.maas.util.mybatis.jpa.littlenb.annotation.mapper.SelectPageDefinition;
import com.maas.util.mybatis.jpa.littlenb.meta.PersistentMeta;
import com.maas.util.mybatis.jpa.littlenb.statement.MyStatementBuildable;

import org.apache.ibatis.builder.BaseBuilder;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.apache.ibatis.session.Configuration;
import org.apache.log4j.Logger;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * 参考 mybatis-jpa-jack  实现的  Enhancer(增强器)
 */
public class PersistentEnhancer extends BaseBuilder {
    public static Logger log = Logger.getLogger(PersistentEnhancer.class.getName());

    /** mybatis */
    protected MapperBuilderAssistant assistant;
    /** mybatis mapper接口类型 */
    protected Class<?> mapper;

    /** 持久化Entity类型 */
    protected Class<?> type;

    StatementFactory statementFactory;

    MyMybatisStatementAdapter adapter;

    /** 持久化Entity元数据 */
    protected PersistentMeta persistentMeta;

    Method method;


    /**
     * 尝试自动获取type 失败！！！！
     * @param mapper
     * @param method
     * @return
     * @throws NoSuchMethodException
     */
    public static Class<?>  getTypeArgClass(Class<?> mapper,Method method) throws NoSuchMethodException {
        Method method2 = mapper.getMethod(method.getName());
        Type returnType = method2.getGenericReturnType();
        Class<?> typeArgClass = null ;
        if(returnType instanceof ParameterizedType){
            ParameterizedType type = (ParameterizedType) returnType;
            Type[] typeArguments = type.getActualTypeArguments();
            for(Type typeArgument : typeArguments){
                typeArgClass = (Class) typeArgument;
                System.out.println("typeArgClass = " + typeArgClass);
            }
        }
        return typeArgClass;
    }

    /**
     * 简单实现domainClass 获取
     * TODO 优化算法或实现
     * @param configuration
     * @param mapper
     * @param statementFactory
     * @param method
     */
    public void definitionDealer(Configuration configuration, Class<?> mapper,StatementFactory statementFactory,Method method) {
        SelectDefinition definition = method.getAnnotation(SelectDefinition.class);
        SelectCountDefinition definition2 = method.getAnnotation(SelectCountDefinition.class);
        SelectPageDefinition definition3 = method.getAnnotation(SelectPageDefinition.class);
        if(definition!=null){
            // Entity type
            this.type = definition.domainClass();
        }else if(definition2!=null){
            this.type = definition2.domainClass();
        }else if(definition3!=null){
            this.type = definition3.domainClass();
        }else {
            try {
                this.type = definition.domainClass();
            } catch (Exception e) {
                System.out.println("您的注解没有 domianClass 属性");
                throw e;
            }
        }
    }
    public PersistentEnhancer(Configuration configuration, Class<?> mapper,StatementFactory statementFactory,Method method) {
        super(configuration);
        String resource = mapper.getName().replace(".", "/") + ".java (best guess)";
        this.assistant = new MapperBuilderAssistant(configuration, resource);
        this.adapter = new MyMybatisStatementAdapter(assistant);
        this.adapter.setMapper(mapper);
        this.statementFactory = statementFactory;
        this.mapper = mapper;

        definitionDealer( configuration,mapper,statementFactory, method);

        // Entity元数据
        this.persistentMeta = new PersistentMeta(type);
        this.method =method;
    }

    /** mapper增强方法入口 */
    public void enhance() {

        String resource = mapper.toString();
        if (!configuration.isResourceLoaded(resource)) {
            configuration.addLoadedResource(resource);
        }
        assistant.setCurrentNamespace(mapper.getName());
        // no cache

        MyStatementBuildable statementBuilder =(MyStatementBuildable)this.statementFactory ;
        statementBuilder.parseStatement(adapter, persistentMeta, method);
    }

}
